#include "ms_asr.h"

int ms_asr_dbg_flag = 0;

__int64 *__fastcall initialize_global_parameters(am_args_t *am_args)
{
  __int64 *result; // x0

  asrp = (__int64)am_args->model_name;
  model_in_len = am_args->model_in_len;
  strip_l = am_args->strip_l;
  strip_r = am_args->strip_r;
  am_args_agc = am_args->agc;
  phone_type = am_args->phone_type;
  am_vcab_cnt = -1;
  dword_167608 = strip_l + strip_r;
  dword_16760C = 8 * (strip_l + strip_r);
  dword_167610 = (strip_l + strip_r) << 10;
  dword_167614 = 8 * model_in_len;
  dword_167618 = (model_in_len + 3) << 7;
  dword_16761C = model_in_len / 8;
  dword_167620 = model_in_len / 8 - strip_l - strip_r;
  dword_167624 = (model_in_len + 3) << 7;
  frams = (model_in_len / 8 - strip_l - strip_r) << 10;
  result = &asrp;
  dword_16762C = ((strip_l + strip_r) << 10) + 384;
  return result;
}

__int64 __fastcall pp_init(__int64 (__fastcall **a1)(__int64), __int64 a2)
{
  unsigned int v3; // [xsp+2Ch] [xbp+2Ch]

  asr_dev = (__int64)a1;
  v3 = (*a1)(a2);
  if ( v3 )
    return v3;
  l_wav_buf = (__int64)malloc(2LL * dword_167624);
  l_wav_buf_agc = (__int64)malloc(2LL * dword_167624);
  l_mel_buf = (__int64)malloc(80 * model_in_len);
  if ( l_wav_buf && l_mel_buf && l_wav_buf_agc )
  {
    pp_clear();
    enable_agc(am_args_agc);
    if ( (ms_asr_dbg_flag & 2) != 0 )
      pp_fw = (__int64)fopen("mic.pcm", "w");
    return 0LL;
  }
  else
  {
    (*(void (**)(void))(asr_dev + 24))();
    return 0xFFFFFFFFLL;
  }
}

int  ms_asr_init(int device_type, char* device_name, am_args_t* am_args, int dbg_flag)
{
    int res;
    int am;
    ms_asr_dbg_flag = dbg_flag;
    initialize_global_parameters(am_args); 
    if(device_type)
    {
        switch (device_type)
        {
        case DEVICE_MIC:
            res = pp_init(dev_mic,device_name);
            break;
        case DEVICE_WAV:
            res = pp_init(dev_wav,device_name);
            break;
        case DEVICE_CUSTOM:
            res = pp_init(dev_custom,device_name);
            break;
        default:
            printf("error device type %d\n", device_type);
            return -1;
        }
    }
    else
    {
        res = pp_init(dev_pcm,device_name);
    }
    if(res)
    {
        printf("pp_init error!\n");
        return -1;
    }else{
        am = am_init(asrp, phone_type);
        if(am)
        {
            printf("am_init error!\n");
            pp_deinit();
            return 1;
        }else{
            return 0;
        }
    }
}

void ms_asr_deinit(unsigned char a1)
{
    if ( (a1 & 1) != 0 )
        decoder_raw_deinit();  
    if ( (a1 & 2) != 0 )
        decoder_dig_deinit();
    if ( (a1 & 4) != 0 )
        decoder_wfst_deinit();
    if ( (a1 & 8) != 0 )
        decoder_kws_deinit();
}

void am_deinit()
{
    am_deinit_model();
    free((void *)qword_146290);
}

void pp_deinit()
{
    free((void *)l_mel_buf);
    free(asr_dev.clear);
    free(asr_dev.read);
    asr_dev->deinit();
    if ( (ms_asr_dbg_flag & 1) != 0 )
    {
      if ( pp_fw )
        fclose((FILE *)pp_fw);
    }
}

void decoder_kws_deinit()
{
  int result;
  result = (int *)(unsigned int)dword_14419C;
  if ( dword_14419C == 1 )
  {
    decoder_kws_clear();
    free((void *)kws_fp);
    kws_fp = NULL;
    qword_143510 = 0LL;
    result = &dword_14419C;
    dword_14419C = 0;
  }
  return result;
}

void decoder_raw_deinit()
{
  raw_flag = 0;
}

void decoder_dig_deinit()
{
  decoder_dig_clear();
  decoder_cb = 0LL;
}

void decoder_wfst_deinit()
{
  if()
}

void decoder_kws_deinit()
{

}

void decoder_deinit(int decoder_type)
{
    if ( (decoder_type & 1) != 0 )
        decoder_raw_deinit();
    if ( (decoder_type & 2) != 0 )
        decoder_dig_deinit();
    if ( (decoder_type & 4) != 0 )
        decoder_wfst_deinit();
    if ( (decoder_type & 8) != 0 )
        decoder_kws_deinit();
}

void ms_asr_deinit(void)
{
    decoder_deinit(255);
    am_deinit();
    pp_deinit();
}
int  ms_asr_decoder_cfg(int decoder_type, decoder_cb_t decoder_cb, void* decoder_args, int decoder_argc)
{
    int result; // w0

    if ( decoder_cb )
      return decoder_init(decoder_type, decoder_cb, decoder_args, decoder_argc);
    decoder_deinit(decoder_type);
    return result;
}

void decoder_raw_clear()
{

}
void decoder_dig_clear()
{

}
void decoder_wfst_clear()
{

}
void decoder_kws_clear()
{

}

void decoder_clear()
{
  decoder_raw_clear();
  decoder_dig_clear();
  decoder_wfst_clear();
  decoder_kws_clear();
}

void ms_asr_clear(void)    //重置内部缓存操作，在开启新的语音识别前清一次 
{
    pp_clear();
    decoder_clear();
}
//frmae: 每次run的帧数; 返回实际run的帧数
//用户可以每次run 1帧，run完做其他处理；或者一个线程里一直run，由外部线程stop来停止
int pp_get()
{
    unsigned int v1; // w0
    unsigned int v2; // w0
    struct timespec v3; // [xsp+10h] [xbp+10h] BYREF
    struct timespec v4; // [xsp+20h] [xbp+20h] BYREF
  
    clock_gettime(1, &v4);
    memmove(asr_dev.clear, (char *)asr_dev.clear + 2 * frams, 2LL * dword_16762C);
    if ( (*((unsigned int (__fastcall **)(char *, _QWORD))asr_dev.init + 1))(
           (char *)asr_dev.clear + 2 * dword_16762C,
           (unsigned int)frams) )
    {
      clock_gettime(1, &v4);
      memcpy(asr_dev.read, asr_dev.clear, 2LL * dword_167624);
      agcProcess(asr_dev.read, 16000LL, 512LL, 2LL);
      if ( (ms_asr_dbg_flag & 0x10) != 0 )
      {
        clock_gettime(1, &v3);
        v1 = utils_cal_dt_us(&v4, &v3);
        printf("%s use %.3f ms\n", "AGC", (double)v1 / 1000.0);
        clock_gettime(1, &v4);
      }
      memmove((void *)l_mel_buf, (const void *)(l_mel_buf + 640 * dword_167620), 640LL * (strip_l + strip_r));
      cal_mel_buf(
        (char *)asr_dev.read + 2048 * (__int64)(strip_l + strip_r),
        l_mel_buf + 640 * (strip_l + strip_r),
        (unsigned int)(8 * dword_167620));
      if ( (ms_asr_dbg_flag & 0x10) != 0 )
      {
        clock_gettime(1, &v3);
        v2 = utils_cal_dt_us(&v4, &v3);
        printf("%s use %.3f ms\n", "CAL_MEL", (double)v2 / 1000.0);
        clock_gettime(1, &v4);
      }
      return l_mel_buf;
    }
    else
    {
      puts("read device error or runout!");
      return 0LL;
    }
}

int am_run(int a1)
{
    unsigned int v1; // w0
    __int64 v2; // x0
    unsigned int v3; // w0
    int v6; // [xsp+24h] [xbp+24h] BYREF
    __int64 v7; // [xsp+28h] [xbp+28h] BYREF
    struct timespec tpend; // [xsp+30h] [xbp+30h] BYREF
    struct timespec tpstart; // [xsp+40h] [xbp+40h] BYREF
    int v10; // [xsp+54h] [xbp+54h]
  
    v10 = 0;
    clock_gettime(1, &tpstart);
    clock_gettime(1, &tpstart);
    v10 = am_infer_model(a1, &v7, &v6);
    if ( (ms_asr_dbg_flag & 0x20) != 0 )
    {
      clock_gettime(1, &tpend);
      v1 = utils_cal_dt_us(&tpstart, &tpend);
      printf("%s use %.3f ms\n", "AM Model", (double)v1 / 1000.0);
      clock_gettime(1, &tpstart);
    }
    if ( v10 )
      return 0LL;
    if ( dword_146298 )
    {
      if ( dword_146298 != 1 )
      {
        printf("Wrong output type %d!\n", (unsigned int)dword_146298);
        return 0LL;
      }
      if ( (ms_asr_dbg_flag & 4) != 0 )
        Xprocess_sort_and_store_data_blocks(v7, dword_16761C, am_vcab_cnt, qword_146290);
      else
        Xprocess_sort_and_store_data_blocks(v7 + am_vcab_cnt * strip_l, dword_167620, am_vcab_cnt, qword_146290);
    }
    else if ( (ms_asr_dbg_flag & 4) != 0 )
    {
      Xsort_and_store_data_blocks(v7, dword_16761C, am_vcab_cnt, qword_146290);
    }
    else
    {
      Xsort_and_store_data_blocks(v7 + 4LL * am_vcab_cnt * strip_l, dword_167620, am_vcab_cnt, qword_146290);
    }
    if ( (ms_asr_dbg_flag & 4) != 0 )
      Xprint_debug_info(qword_146290);
    v2 = ms_asr_dbg_flag & 0x20;
    if ( (ms_asr_dbg_flag & 0x20) != 0 )
    {
      clock_gettime(1, &tpend);
      v3 = utils_cal_dt_us(&tpstart, &tpend);
      printf("%s use %.3f ms\n", "decode_result", (double)v3 / 1000.0);
      v2 = clock_gettime(1, &tpstart);
    }
    v10 = am_infer_clean(v2);
    if ( v10 )
      return 0LL;
    if ( (ms_asr_dbg_flag & 4) != 0 )
      return qword_146290 + 80LL * strip_l;
    else
      return qword_146290;
}

int  ms_asr_run(int frame)
{
    __int64 v3; // [xsp+28h] [xbp+28h]
    __int64 v4; // [xsp+30h] [xbp+30h]
    int i; // [xsp+3Ch] [xbp+3Ch]
  
    for ( i = 0; i < frame; ++i )
    {
      v4 = pp_get();
      if ( !v4 )
        break;
      v3 = am_run(v4);
      if ( !v3 )
        break;
      decoder_run(v3);
    }
    return i;                                     // 实际帧数
}

int ms_asr_get_frame_time(void) //返回一帧的时间 ms
{

}
void ms_asr_get_am_vocab(char** vocab, int* cnt)
{

}
int ms_asr_set_dev(int device_type, char* device_name) //重新设置asr的数据源，一般在pcm/wav识别时使用
{

}
int ms_asr_kws_reg_similar(char* pny, char** similar_pnys, int similar_cnt)
{

}
void ms_asr_wfst_run(pnyp_t* pnyp_list) //输入 T_CNT*BEAM_CNT 个拼音结果，进行decoder推理，用于lm的测试
{
  decoder_run(pnyp_list);
}
//int ms_asr_get_frame_time(void); //返回一帧的时间 ms